import json
import multiprocessing
from datetime import datetime
from urllib.parse import urljoin
from collections import defaultdict

import requests
from celery import current_app

from celery_app.app import app
from mock import Mock


@app.task
def add(p1, p2, **kwargs):
    print(Mock.mock('@float(3,5,2,2)') + Mock.mock('@float(3,5,2,2)'))


@app.task
def publish(url, data, **kwargs):
    auth = kwargs.get('auth', None)
    auth = tuple(auth) if auth else None
    requests.post(url, data, auth=auth)


@app.task
def mock_value(sys_name, **kwargs):
    sandman_url = urljoin(current_app.conf['SANDMAN2_URL'], sys_name)
    res = requests.get(sandman_url)
    if res.status_code == 200:
        resources = json.loads(res.text).get('resources')
        min_count = int(kwargs['min_count'])
        max_count = int(kwargs['max_count'])
        max_count = len(resources) if max_count > len(resources) else max_count

        exp = {}
        for resource in resources:
            if 'mock' in resource:
                exp[str(resource['serial'])] = resource['mock']

        mock_exp = {
            "object|{0}-{1}".format(min_count, max_count): exp
        }
        res = Mock.mock(mock_exp)
        if 'object' in res:
            for k, v in res['object'].items():
                requests.put(sandman_url + '/' + k, json.dumps(
                    {'value': v, 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')}))


@app.task
def mock_alarm(*systems, **kwargs):
    min_system = int(kwargs['min_system'])
    max_system = int(kwargs['max_system'])
    sys_min_count = int(kwargs['sys_min_count'])
    sys_max_count = int(kwargs['sys_max_count'])
    alarm_desc = kwargs['alarm_desc']
    normal_desc = kwargs['normal_desc']
    during_min = int(kwargs['during_min'])
    during_max = int(kwargs['during_max'])

    sys_dict = {}
    for sys_name in systems:
        sys_dict[sys_name] = "@integer({0}, {1})".format(sys_min_count, sys_max_count)

    mock_exp = {
        "object|{0}-{1}".format(min_system, max_system): sys_dict
    }

    res = Mock.mock(mock_exp)
    exp = {}
    if 'object' not in res:
        return

    for k, v in res['object'].items():
        sandman_url = urljoin(current_app.conf['SANDMAN2_URL'], k)
        sandman_res = requests.get(sandman_url)
        if sandman_res.status_code != 200:
            continue
        resources = json.loads(sandman_res.text).get('resources')
        for resource in resources:
            if 'alarm' not in resource:
                continue
            exp[str(resource['serial'])] = {"alarm|1": alarm_desc,
                                            "during": "@integer({0}, {1})".format(during_min, during_max)}

        mock_exp = {
            "object|{0}".format(v): exp
        }

        alarm_json_data = Mock.mock(mock_exp)
        if 'object' not in alarm_json_data:
            continue
        for serial, obj in alarm_json_data['object'].items():
            url = sandman_url + '/' + serial
            requests.put(url, json.dumps({'alarm': obj['alarm']}))
            remove_alarm.apply_async((url, normal_desc), countdown=obj['during'])


@app.task
def remove_alarm(url, desc):
    requests.put(url, json.dumps({'alarm': desc}))



if __name__ == '__main__':
    mgr = multiprocessing.Manager()
    sequence = mgr.dict()
@app.task
def mock_employees(*patrols, **kwargs):
    if len(patrols) < 2:
        return
    empolyees = kwargs['employees']
    url = urljoin(current_app.conf['SANDMAN2_URL'], 'employees')
    res = requests.get(url)
    if res.status_code != 200:
        return
    resources = json.loads(res.text).get('resources')
    min_count = int(kwargs['min_count'])
    max_count = int(kwargs['max_count'])
    max_count = len(resources) if max_count > len(resources) else max_count

    patrol_value = defaultdict(int)
    exp = {}
    for resource in resources:
        if resource['serial'] not in empolyees:
            continue
        if 'patrol_serial' in resource:
            patrol_serial = resource['patrol_serial']
            exp[str(resource['serial'])] = patrol_serial or 0
            if patrol_serial:
                patrol_value[patrol_serial] += 1

    mock_exp = {
        "object|{0}-{1}".format(min_count, max_count): exp
    }

    res = Mock.mock(mock_exp)
    if 'object' not in res:
        return
    for k, v in res['object'].items():
        old_patrol_serial = v
        if v not in patrols:
            v = patrols[0]
        else:
            index = patrols.index(v)
            global sequence
            if k not in sequence:
                sequence[k] = True
            if sequence[k]:  # 顺序
                if index == len(patrols) - 1:  # 最后一个分站
                    sequence[k] = False
                    v = patrols[-2]
                else:
                    v = patrols[index + 1]
            else:  # 逆序
                if index == 0:  # 第一个分站
                    sequence[k] = True
                    v = patrols[1]
                else:
                    v = patrols[index - 1]
        new_patrol_serial = v
        res = requests.put(url + '/' + k, json.dumps({'patrol_serial': v}))
        if res.status_code == 200:
            patrol_url = urljoin(current_app.conf['SANDMAN2_URL'], 'patrols')
            if old_patrol_serial:
                res = requests.put(patrol_url + '/' + str(old_patrol_serial),
                                   json.dumps({'value': patrol_value[old_patrol_serial] - 1}))
                if res.status_code == 200:
                    patrol_value[old_patrol_serial] -= 1
            res = requests.put(patrol_url + '/' + str(new_patrol_serial),
                               json.dumps({'value': patrol_value[new_patrol_serial] + 1}))
            if res.status_code == 200:
                patrol_value[new_patrol_serial] += 1


@app.task
def mock_accesses():
    emp_url = urljoin(current_app.conf['SANDMAN2_URL'], 'employees')
    res = requests.get(emp_url)
    if res.status_code != 200:
        return
    resources = json.loads(res.text).get('resources')
    emp = {}
    for resource in resources:
        emp[resource['serial']] = resource['name']

    access_url = urljoin(current_app.conf['SANDMAN2_URL'], 'accesses')
    res = requests.get(access_url)
    if res.status_code != 200:
        return
    resources = json.loads(res.text).get('resources')
    mock_exp = {
        "object|{0}".format(len(resources)): emp
    }
    res = Mock.mock(mock_exp)
    if 'object' not in res:
        return
    mock_res = res['object']
    mock_res_keys = list(mock_res.keys())
    for index, resource in enumerate(resources):
        if index == len(mock_res):
            return
        staff_serial = mock_res_keys[index]
        staff_name = mock_res[staff_serial]
        requests.put(access_url + '/' + str(resource['serial']),
                     json.dumps({'staff_serial': staff_serial, 'staff_name': staff_name}))
